<script setup lang="ts">
import { ref, computed, watchEffect, watch, useTemplateRef, getCurrentInstance, shallowReactive, onBeforeUnmount, reactive, shallowRef, triggerRef, nextTick } from "vue";
import { load, dump } from "js-yaml"
import { fileInfo } from '../../types'
import * as types from "../types";
import { message } from 'ant-design-vue'

const comApi = useTemplateRef('refApi')
const comModel = useTemplateRef('refModel')
const saveEvent = async function (event) {
    if (showLoading.value) return
    // 检查是否按下了 Control 键和 S 键
    if (event.key === 's' && (event.ctrlKey || event.metaKey)) {
        event.preventDefault();
        if (comApi.value != null) {
            let res = comApi.value.checkName()
            if (res) {
                delete data['api'][res.from]
                data['api'][res.to] = apiData.method
                refreshGroupApi()
            }
        }
        else {
            comModel.value?.checkName()
            triggerRef(models)
        }
        showLoading.value = true
        await window.api.saveFile(chooseFile.value, dump(data))
        showLoading.value = false
    } else if (event.key === 'f' && (event.ctrlKey || event.metaKey)) {
        search.enable = true
        nextTick(() => {
            (searchRef.value as any).focus()
        })
    } else if (event.key === 'Escape' && search.enable) {
        search.enable = false
        search.value = ""
    }
}
document.addEventListener('keydown', saveEvent);
onBeforeUnmount(() => {
    document.removeEventListener('keydown', saveEvent);
    window.api.offEvent('watch', reload)
})
const props = defineProps<{ project: types.projectSetting }>()
const endpoints = ref<{ [key: string]: types.method }>({})
const groupApi = ref<{ [key: string]: types.methodWithUrl[] }>({})
const models = shallowRef<{ [key: string]: types.model }>({})
const apiData = shallowReactive<types.methodWithUrl>({ url: '', method: { desc: '', func: '', response: '' } })
const modelData = ref<string>('')
const kind = ref<types.viewKind>("")
const search = reactive({
    value: '',
    enable: false
})
const searchRef = useTemplateRef('searchRef')
const showLoading = ref(false)
let urlPre = ""
let data: any = null

let files = ref<fileInfo[]>([])
let chooseFile = ref("")
watchEffect(async () => {
    if (props.project?.path) {
        files.value = await window.api.getProject(props.project.path)
        dbs = Object.keys(window.db)
        window.api.watchDir(props.project.path)
        window.api.onWatchDir(reload)
    }
})
const showFiles = computed(() => {
    if (search.value == '') return files.value
    else return files.value.filter(file => file.name.includes(search.value))
})
function reload(path: string) {
    if (path == chooseFile.value) {
        chooseFile.value = ''
    }
}
const ins = getCurrentInstance()!
watch(chooseFile, async () => {
    if (chooseFile.value != '') {
        const s = await window.api.getFile(chooseFile.value)
        data = load(s)
        models.value = data['model']
        ins.appContext.config.globalProperties.$model = data['model']
        endpoints.value = data['api']
        refreshGroupApi()
    } else {
        models.value = {}
        endpoints.value = {}
        groupApi.value = {}
    }
    kind.value = ""
})
function refreshGroupApi() {
    let urls = Object.keys(data['api'])
    if (urls.length == 0) return
    if (urls.length == 1) urlPre = urls[0].substring(0, urls[0].lastIndexOf('/'))
    calcUrlPre(urls)
    let tApi: { [key: string]: types.methodWithUrl[] } = {}
    for (const key in data['api']) {
        let url = key.split(' ')[1]
        let pre = url.substring(urlPre.length + 1).split('/')[0]
        if (pre in tApi) {
            tApi[pre].push({ url: key, method: data['api'][key] })
        } else {
            tApi[pre] = [{ url: key, method: data['api'][key] }]
        }
    }
    groupApi.value = tApi
}
function calcUrlPre(arr: string[]) {
    let res: string[] = arr[0].split(' ')[1].split('/')
    for (let index = 1; index < arr.length; index++) {
        const element = arr[index].split(' ')[1];
        let arr2 = element.split('/')
        for (let i = 0; i < res.length && i < arr2.length; i++) {
            if (res[i] != arr2[i]) {
                res = res.slice(0, i)
            }
        }
    }
    urlPre = res.join('/')
}
const modelNames = computed(() => {
    return Object.keys(models.value).sort()
})
function selectApi(url: string) {
    apiData.url = url
    apiData.method = data['api'][url]
    kind.value = 'api'
}
function selectModel(name: string) {
    modelData.value = name
    kind.value = 'model'
}
function rename(k: types.viewKind, from: string, to: string) {
    if (k == 'api') {
        const t = data['api'][from]
        delete data['api'][from]
        data['api'][to] = t
        refreshGroupApi()
    } else {
    }
}
//#region 添加操作
function addApi() {
    if (!('GET /' in data['api'])) {
        data['api']['GET /'] = { desc: '新接口', func: '' }
    }
    selectApi('GET /')
}
function addModel(dbInfo: types.model | null = null) {
    if (dbInfo != null) {
        data['model'][''] = dbInfo.model
    } else if (!('' in data['model'])) {
        data['model'][''] = []
    }
    selectModel('')
}
//#endregion
//#region 右键菜单
function handleRightClick(event: any, type: string, url: string) {
    if (event.key == 'copy') {
        if (type == 'api') {
            let ori = data['api'][url]
            ori = structuredClone(ori)
            endpoints.value[url + 'copy'] = ori
            refreshGroupApi()
            selectApi(url + 'copy')
        } else {
            let ori = data['model'][url]
            ori = structuredClone(ori)
            models.value[url + ' copy'] = ori
            selectModel(url + ' copy')
        }
    } else if (event.key == 'del') {
        if (type == 'api') {
            delete data['api'][url]
            refreshGroupApi()
        } else {
            delete models.value[url]
        }
    }
}
//#endregion
// #region 根据 db 创建 model
const createByDb = reactive({
    'model': false,
    'selected': ''
})
let dbs = Object.keys(window.db)
function createModel() {
    const db = window.db[createByDb.selected]
    let name = createByDb.selected
    if (name == '') {
        message.error('请选择数据库')
        return
    }
    while (name in models.value) {
        name += 'copy'
    }
    models.value[name] = structuredClone(db)
    selectModel(name)
    createByDb.selected = ''
    createByDb.model = false
}
// #endregion
</script>

<template>
    <a-layout has-sider>
        <a-layout-sider id="fileList">
            <a-input v-model:value="search.value" v-show="search.enable" id="search" ref="searchRef" />
            <a-list size="small" :data-source="showFiles">
                <template #renderItem="{ item }">
                    <a-list-item class="files" @click="chooseFile = item.path">{{ item.name }}</a-list-item>
                </template>
            </a-list>
        </a-layout-sider>
        <a-layout-content :style="{ marginLeft: '200px' }">
            <custom-move>
                <template #left>
                    <div class="title">
                        <h2>Endpoints</h2>
                        <a-button v-show="chooseFile != ''" class="title-btn" @click="addApi">添加</a-button>
                    </div>
                    <a-collapse expand-icon-position="end">
                        <a-collapse-panel v-for="(item, index) in groupApi" :header="index" :key="index">
                            <a-list size="small" :data-source="item">
                                <template #renderItem="{ item }">
                                    <a-dropdown :trigger="['contextmenu']">
                                        <a-list-item @click="selectApi(item.url)">{{ item.method.desc || "无"
                                            }}</a-list-item>
                                        <template #overlay>
                                            <a-menu @click="(info) => handleRightClick(info, 'api', item.url)">
                                                <a-menu-item key="copy">复制</a-menu-item>
                                                <a-menu-item key="del">删除</a-menu-item>
                                            </a-menu>
                                        </template>
                                    </a-dropdown>
                                </template>
                            </a-list>
                        </a-collapse-panel>
                    </a-collapse>
                    <div class="title">
                        <h2>Models</h2>
                        <a-dropdown v-if="chooseFile != ''" class="title-btn">
                            <template #overlay>
                                <a-menu>
                                    <a-menu-item key="1" @click="addModel()">新建空白模型</a-menu-item>
                                    <a-menu-item key="2" @click="createByDb.model = true">基于表新建模型</a-menu-item>
                                </a-menu>
                            </template>
                            <a-button>
                                添加
                                <DownOutlined />
                            </a-button>
                        </a-dropdown>
                    </div>
                    <a-list size="small" :data-source="modelNames">
                        <template #renderItem="{ item }">
                            <a-dropdown :trigger="['contextmenu']">
                                <a-list-item @click="selectModel(item)">{{ item }}</a-list-item>
                                <template #overlay>
                                    <a-menu @click="(info) => handleRightClick(info, 'model', item)">
                                        <a-menu-item key="copy">复制</a-menu-item>
                                        <a-menu-item key="del">删除</a-menu-item>
                                    </a-menu>
                                </template>
                            </a-dropdown>
                        </template>
                    </a-list>
                </template>
                <template #right>
                    <div style="padding: 16px;">
                        <api-view ref="refApi" v-if="kind == 'api'" v-model="apiData" @rename="rename"></api-view>
                        <model-view ref="refModel" v-else-if="kind == 'model'" :model="modelData"></model-view>
                    </div>
                </template>
            </custom-move>
        </a-layout-content>
    </a-layout>
    <a-modal v-model:open="createByDb.model" title="选择数据表" @ok="createModel()">
        <a-select style="width: 100%;" v-model:value="createByDb.selected" :showSearch="true">
            <a-select-option value="">请选择</a-select-option>
            <a-select-option v-for="item in dbs" :value="item">{{ item }}</a-select-option>
        </a-select>
    </a-modal>
    <div v-show="showLoading" class="full-screen-loading">
        <a-spin size="large" />
    </div>
</template>

<style>
.title {
    display: flex;
    justify-content: center;
    /* 使所有子元素在主轴上居中 */
    align-items: center;
    /* 使所有子元素在交叉轴上居中，这里其实可以省略因为默认就是居中 */
}

.title h2 {
    flex: 1;
    /* 让 h2 占据剩余的空间，从而居中 */
    text-align: center;
    /* 使 h2 文本居中 */
}

.title-btn {
    margin-left: auto;
    margin-right: 10px;
}

#fileList {
    overflow: auto;
    padding-top: 50px;
    height: 100vh;
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
}

#fileList::-webkit-scrollbar {
    width: 0px;
}

.files {
    color: gold !important;
    text-align: left;
}

.ant-collapse-content-box {
    padding: 0px !important;
}

.full-screen-loading {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(1, 1, 1, 0.5);
    /* 确保加载界面位于最上层 */
    z-index: 9999;
}
</style>